<template>
  <div class="goods-sku">
    <dl v-for="(spec, index) in goods.specs" :key="spec.id">
      <dt>{{spec.name}}</dt>
      <dd>
        <template v-for="btn in spec.values" :key="btn.name">
          <img :class="{selected: btn.selected, disabled: btn.disabled}" @click="changeSku(btn, spec)" v-if="btn.picture" :src="btn.picture" alt="">
          <span :class="{selected: btn.selected, disabled: btn.disabled}" @click="changeSku(btn, spec)" v-else>{{btn.name}}</span>
        </template>
      </dd>
    </dl>
  </div>
</template>
<script>
import bwPowerSet from '@/vendor/power-set.js'
// 演示一下bwPowerSet的使用
// console.log(bwPowerSet(['蓝色', '10cm', '中国']))
// 封装一个方法  根据goods.skus  整理路径字典
const spliter = '☆'
const getPathMap = (skus) => {
  const pathMap = {}
  // 1. 过滤出有库存的 有效sku  即inventory(库存)不为0
  skus
    .filter(sku => sku.inventory > 0)
    // filter返回还是数组,链式调用循环
    .forEach(sku => {
      // 2. 找到了符合条件的sku  可以去进行处理了 将规格数据处理成算法需要的形式
      const arr = sku.specs.map(item => item.valueName)
      // console.log('arr', arr)
      // 3. 使用算法求子集 算法需要的数据是['黑色','30cm', '日本']
      const sets = bwPowerSet(arr)
      // console.log('sets', sets)
      // console.log(sku)
      // 4. 整理子集, 组合字典 => {}
      sets.forEach(set => {
        // 用个五角星就是为了让同学们看清条件 把子集数组转换成字符串
        const key = set.join(spliter)
        // console.log('key', key)
        // [sku.id] 相当于  pathMap[key] = []   pathMap[key].push(sku.id)
        // 当没有pathMap对象没有这个key的时候 新建一个属性  key: [id]  如果有这个key值了 直接push(id)
        // 如果值不用数组,会被其他的sku 把id给覆盖掉 咱们这是两层循环
        if (pathMap[key]) {
          pathMap[key].push(sku.id)
        } else {
          // pathMap = {} 是个空对象
          // pathMap['黑色'] = [1] ===> {'黑色': [sku.id]}
          pathMap[key] = [sku.id]
        }
      })
    })
  return pathMap
}
// 想要获取选中规格的名字
// 得到的结果得保证顺序   [undefined,undefined,undefined][
// ['黑色',undefined,undefined]
// [undefined,'30cm',undefined]
// [undefined,undefined,'中国']
const getSelectedSpec = (specs) => {
  const arr = []
  specs.forEach((spec, index) => {
    // spec  是每一行
    // 一行按钮里  只能有一个选中的
    const btn = spec.values.find(obj => obj.selected === true)
    if (btn) {
      // 选中了 ,将选中的名字 存到数组的对应项中(spec行)
      arr[index] = btn.name
    } else {
      // 没找到,这一行没选中 存个undefined
      arr[index] = undefined
    }
  })
  return arr
}
// 核心逻辑: 遍历按钮 然后看在不在字典里
// 初始化的时候 判断单个按钮就行
// 点击按钮之后,需要组合起来判断在不在字典里
const updateDisabledStatus = (specs, pathMap) => {
  // 引用类型备份,最好JSON.stringify()深拷贝一下
  const selectedJSON = JSON.stringify(getSelectedSpec(specs))
  // console.log(selectedJSON)
  // 遍历之后获取到每一行按钮
  specs.forEach((spec, i) => {
    // 遍历获取到每一个按钮 如果没有选中的,就是判断单个按钮在不在字典里
    // 一旦有选中的,就需要把    将要选中的项 和已选中的组合
    // spec.values 是每一行按钮
    spec.values.forEach(btn => {
      // 每一次打印一下btn
      // console.log(btn.name)
      // 是每一个按钮 i是第几行
      const selectedArr = JSON.parse(selectedJSON)
      // 把所有下次可能点击的按钮名称拼接一下
      // 赋值的是下一次 可能点击按钮 [undefined, '20cm', '中国']   => ['黑色', '20cm', '中国'] [undefined, '30cm', '中国']
      // i是第几行
      selectedArr[i] = btn.name
      // 获取的全部可切换的选项
      // console.log('selectedArr', selectedArr)
      // 如果不筛选 ['蓝色', undefined, '中国']  蓝色☆☆中国
      // 数据筛选一下,筛选出不为undefined的名字再拼接 简写(v=>v) ===  (v => { if(v) {return v} })
      const key = selectedArr.filter(v => v).join(spliter)
      // 处理之后的数组join拼接成 蓝色☆中国
      // console.log('key', key)
      // 在字典里就不禁用,  不在字典里就禁用
      if (pathMap[key]) {
        btn.disabled = false
      } else {
        btn.disabled = true
      }
    })
  })
}

const initDefaultStatus = (goods, skuId) => {
  // 1 从skus中根据skuId 找到选中项
  const sku = goods.skus.find(item => item.id === skuId)
  // 2 需要控制按钮的高亮
  // console.log('sku++++', sku)
  if (sku) {
    goods.specs.forEach((spec, i) => {
      spec.values.forEach(btn => {
        // console.log(sku)
        btn.selected = btn.name === sku.specs[i].valueName
      })
    })
  }
}
export default {
  name: 'GoodsSku',
  props: {
    goods: {
      type: Object,
      default: () => ({
        specs: [],
        skus: []
      })
    },
    skuId: {
      type: String,
      default: ''
    }
  },
  setup (props, context) {
    // 进入页面如果传入了skuId  ,默认按照skuId进行高亮也就是 selected给个true
    if (props.skuId) {
      initDefaultStatus(props.goods, props.skuId)
    }
    // 获取路径字典
    const pathMap = getPathMap(props.goods.skus)
    // console.log('pathMap', pathMap)
    // 初始化的时候更新一下按钮状态
    updateDisabledStatus(props.goods.specs, pathMap)
    const changeSku = (btn, spec) => {
      // 做个健全 如果不可点击直接返回
      if (btn.disabled) return
      // 我们给选中的加一个选中的属性
      if (btn.selected) {
        btn.selected = false
      } else {
        // 只需我自己放火,其他的都给我灭了 先取消所有 再选中自己
        spec.values.forEach(item => {
          item.selected = false
        })
        btn.selected = true
      }
      // 点击的时候也需要更新按钮状态
      updateDisabledStatus(props.goods.specs, pathMap)
      // 按顺序获取选中按钮 ['a' , 'b', undefinde]
      const selectedArr = getSelectedSpec(props.goods.specs).filter(v => v)
      if (selectedArr.length === props.goods.specs.length) {
        const skuId = (pathMap[selectedArr.join(spliter)][0])
        const sku = props.goods.skus.find(sku => sku.id === skuId)
        // console.log('sku++++++++++++++', sku)
        context.emit('change', {
          skuId: sku.id,
          price: sku.price,
          oldPrice: sku.oldPrice,
          inventory: sku.inventory,
          specsText: sku.specs.reduce((str, item) => `${str} ${item.name}：${item.valueName}`, '').trim('')
        })
      } else {
        // 有没选中的
        context.emit('change', {})
      }
      // console.log('selectedArr', selectedArr)
    }

    return {
      changeSku
    }
  }
}
</script>
<style scoped lang="less">
.sku-state-mixin () {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;
  &.selected {
    border-color: @xtxColor;
  }
  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}
.goods-sku {
  padding-left: 10px;
  padding-top: 20px;
  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;
    dt {
      width: 50px;
      color: #999;
    }
    dd {
      flex: 1;
      color: #666;
      > img {
        width: 50px;
        height: 50px;
        .sku-state-mixin ();
      }
      > span {
        display: inline-block;
        height: 30px;
        line-height: 28px;
        padding: 0 20px;
        .sku-state-mixin ();
      }
    }
  }
}
</style>
